package io.github.kimmking.gateway.outbound.okhttp;

import io.github.kimmking.gateway.constant.GConstant;
import io.github.kimmking.gateway.exception.RequestException;
import io.github.kimmking.gateway.filter.HeaderHttpResponseFilter;
import io.github.kimmking.gateway.filter.HttpRequestFilter;
import io.github.kimmking.gateway.filter.HttpResponseFilter;
import io.github.kimmking.gateway.outbound.common.HttpOutboundHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import okhttp3.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.HTTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

public class OkhttpOutboundHandler implements HttpOutboundHandler {

    private List<String> backendUrls;
    OkHttpClient okHttpClient;

    HttpResponseFilter filter = new HeaderHttpResponseFilter();

    private static Logger logger = LoggerFactory.getLogger(OkhttpOutboundHandler.class);

    public OkhttpOutboundHandler(List<String> backendUrls) {
        this.backendUrls = backendUrls;
        this.okHttpClient = new OkHttpClient().newBuilder().readTimeout(3000, TimeUnit.MILLISECONDS)
                .writeTimeout(3000, TimeUnit.MILLISECONDS)
                .connectionPool(new ConnectionPool(400, 5000, TimeUnit.MILLISECONDS))
                .build();

    }

    @Override
    public void handle(final FullHttpRequest fullRequest, final ChannelHandlerContext ctx, HttpRequestFilter filter) {
        //通过线程池异步转发结果增加并发
        //创建连接池
        filter.filter(fullRequest, ctx);
        HttpHeaders headers = fullRequest.headers();
        String uri = fullRequest.uri();
        HttpVersion httpVersion = fullRequest.protocolVersion();
        //获得url
        String route = GConstant.ROUTER.route(this.backendUrls);
        //http://localhost:8802
        HttpResponse httpResponse = null;

        if (HttpMethod.GET.equals(fullRequest.method())) {
            httpResponse = doGet(route + uri, headers, ctx, httpVersion);
        } else if (HttpMethod.POST.equals(fullRequest.method())) {
            httpResponse = doPost(route + uri, headers, ctx, httpVersion, fullRequest.content());
        } else {
            httpResponse = new HttpResponse(ctx, httpVersion);
        }
        FullHttpResponse response = httpResponse.getFullHttpResponse(3000);
        this.filter.filter(response);
        ctx.write(response);
    }

    public HttpResponse doGet(String url, HttpHeaders headers, final ChannelHandlerContext ctx, HttpVersion httpVersion) {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        for (Map.Entry<String, String> entry : headers.entries()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }
        Request request = requestBuilder.get().build();
        Call call = this.okHttpClient.newCall(request);
        HttpResponse httpResponse = new HttpResponse(ctx, httpVersion);
        call.enqueue(httpResponse);
        return httpResponse;
    }

    public HttpResponse doPost(String url, HttpHeaders headers, final ChannelHandlerContext ctx, HttpVersion httpVersion, ByteBuf content) {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        for (Map.Entry<String, String> entry : headers.entries()) {
            requestBuilder.addHeader(entry.getKey(), entry.getValue());
        }
        RequestBody requestBody = RequestBody.create(MediaType.parse(headers.get("Content-Type")), ByteBufUtil.getBytes(content));

        Request request = requestBuilder.post(requestBody).build();
        Call call = this.okHttpClient.newCall(request);
        HttpResponse httpResponse = new HttpResponse(ctx, httpVersion);
        call.enqueue(httpResponse);
        return httpResponse;
    }
}
